package com.onekbase.demo.tcp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class TcpGatewaySelectorDemo {
    public static void main(String[] args) throws IOException, InterruptedException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.bind(new InetSocketAddress("localhost", 8083));
        System.out.println("Server started on port 8083");
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            selector.select();
            Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                try {
                    if (key.isAcceptable()) {
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int bytesRead = socketChannel.read(buffer);
                        if (bytesRead == -1) {
                            socketChannel.close();
                            keyIterator.remove();
                            continue;
                        }
                        if (bytesRead <= 0) {
                            keyIterator.remove();
                            continue;
                        }
                        Attach at = (Attach) key.attachment();
                        if (at != null && "proxy".equals(at.getType())) {
                            buffer.flip();
                            byte[] data = new byte[bytesRead];
                            buffer.get(data);
                            String response = new String(data);
                            System.out.println("serverclient Received response: " + response);
                            socketChannel.close();
                            SocketChannel server = at.getChannel();
                            Attach sat = new Attach(server, "server", response);
                            server.register(selector, SelectionKey.OP_WRITE, sat);
                        } else {
                            buffer.flip();
                            byte[] data = new byte[buffer.remaining()];
                            buffer.get(data);
                            String receivedData = new String(data);
                            System.out.println("Received: " + receivedData);

                            SocketChannel socketChannel2 = SocketChannel.open();
                            socketChannel2.connect(new InetSocketAddress("localhost", 8084));
                            socketChannel2.configureBlocking(false);
                            String request = "Request data from server client";
                            ByteBuffer buffer2 = ByteBuffer.wrap(request.getBytes());
                            socketChannel2.write(buffer2);
                            Attach pat = new Attach(socketChannel, "proxy", null);
                            socketChannel2.register(selector, SelectionKey.OP_READ, pat);
                        }
                    } else if (key.isWritable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        Attach at = (Attach) key.attachment();

                        String response = at.getRep();
                        ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                        socketChannel.write(responseBuffer);
                        socketChannel.close();
                    }
                    keyIterator.remove();
                }catch (Exception e){
                    e.printStackTrace();
                    keyIterator.remove();
                }
            }
        }
    }

    static class Attach{
        SocketChannel channel;
        String type ;
        String rep;

        public Attach(SocketChannel channel, String type,String rep) {
            this.channel = channel;
            this.type = type;
            this.rep=rep;
        }

        public SocketChannel getChannel() {
            return channel;
        }

        public void setChannel(SocketChannel channel) {
            this.channel = channel;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getRep() {
            return rep;
        }

        public void setRep(String rep) {
            this.rep = rep;
        }
    }

}